<script lang="ts">
	import { userIdentity } from '$lib/Data/AniList/identity';
	import { user } from '$lib/Data/AniList/user';
	import type { Badge } from '$lib/Database/badges';
	// import { domToBlob } from 'modern-screenshot';
	import { onMount } from 'svelte';
	import HeadTitle from '$lib/Home/HeadTitle.svelte';
	import { databaseTimeToDate, dateToDatabaseTime } from '$lib/Utility/time';
	import root from '$lib/Utility/root.js';
	import tooltip from '$lib/Tooltip/tooltip.js';
	import proxy from '$lib/Utility/proxy.js';
	import cdn from '$lib/Utility/cdn.js';
	import locale from '$stores/locale.js';
	import Skeleton from '$lib/Loading/Skeleton.svelte';
	import Message from '$lib/Loading/Message.svelte';
	import Dropdown from '$lib/Dropdown.svelte';
	import AnimeRateLimited from '$lib/Error/AnimeRateLimited.svelte';
	import { activityText } from '$lib/Data/AniList/activity.js';
	import SettingHint from '$lib/Settings/SettingHint.svelte';
	import Popup from '$lib/Popup.svelte';
	import FallbackImage from '$lib/FallbackImage.svelte';
	// import { io } from 'socket.io-client';

	export let data;

	interface ImportImage {
		link?: string;
		image: string;
	}

	let editMode = false;
	let importMode = false;
	let currentUserIdentity: ReturnType<typeof userIdentity>;
	let error: null | string;
	// const socket = io();
	let badgesPromise: Promise<Response>;
	let awcPromise: Promise<Response>;
	// let dark = true;
	// let transparent = false;
	let confirmDelete = 0;
	let confirmPrune = 0;
	let selectedBadge: Badge | undefined = undefined;
	let loadError: string | null = null;
	const isId = /^\d+$/.test(data.username);
	let importImages: ImportImage[] | undefined = undefined;
	// let badgeCount = 0;
	let importLinks = false;
	let importCategory = '';
	let importReplies = false;

	// $: downloadDisabled = badgeCount > 20;

	type GroupedBadges = { [key: string]: Badge[] };

	interface AWCBadge {
		link: string;
		description: string;
		image: string;
	}

	interface AWCBadgesGroup {
		group: string;
		badges: AWCBadge[];
	}

	onMount(async () => {
		// socket.on('badges', (message) => (badges = message));

		const badger = isId
			? {
					id: parseInt(data.username),
					name: 'User'
			  }
			: await user(data.username);

		if (!isId && !badger) {
			loadError = 'User not found.';

			return;
		}

		badgesPromise = fetch(root(`/api/badges?id=${badger.id}`));
		awcPromise = fetch(proxy(`https://awc.moe/challenger/${badger.name}`));

		if (data.user && !isId) {
			currentUserIdentity = userIdentity(data.user);

			// socket.emit('badges', data.user);
		} else {
			currentUserIdentity = new Promise((resolve) =>
				resolve({
					name: 'Guest',
					id: -1,
					avatar: 'https://s4.anilist.co/file/anilistcdn/user/avatar/large/default.png'
				})
			);
		}
	});

	// const fallback = (event: Event, image: string | undefined) =>
	// 	setTimeout(() => ((event.target as HTMLImageElement).src = image || ''), 1000);

	// const awcBadges = (awcResponse: string): AWCBadge[] => {
	// 	return Array.from(
	// 		new DOMParser().parseFromString(awcResponse, 'text/html').querySelectorAll('.badge-display a')
	// 	).map((b) => {
	// 		const badge = b as HTMLAnchorElement;
	// 		const image = badge.querySelector('img') as HTMLImageElement;

	// 		return {
	// 			link: badge.href,
	// 			description: image.alt,
	// 			image: image.src
	// 		};
	// 	});
	// };

	const awcBadgesGrouped = (awcResponse: string): AWCBadgesGroup[] => {
		return Array.from(
			new DOMParser().parseFromString(awcResponse, 'text/html').querySelectorAll('.container')
		)
			.map((c) => {
				const container = c as HTMLDivElement;
				const header = container.querySelector('.container-header') as HTMLDivElement;

				if (!header) return;

				if (!['Anime', 'Manga', 'Special'].includes(header.innerText)) return;

				if (header.innerText === 'Special') {
					return {
						group: header.innerText,
						badges: Array.from(container.querySelectorAll('.badge-display img')).map((b) => {
							const badge = b as HTMLImageElement;

							return {
								link: '#',
								description: badge.alt,
								image: badge.src.includes('placeholder')
									? cdn('https://awc.moe/static/images/badge-placeholder.png')
									: badge.src
							};
						})
					};
				}

				return {
					group: header.innerText,
					badges: Array.from(container.querySelectorAll('.badge-display a')).map((b) => {
						const badge = b as HTMLAnchorElement;
						const image = badge.querySelector('img') as HTMLImageElement;

						return {
							link: badge.href,
							description: image.alt,
							image: image.src.includes('placeholder')
								? cdn('https://awc.moe/static/images/badge-placeholder.png')
								: image.src
						};
					})
				};
			})
			.filter((b) => b !== undefined) as AWCBadgesGroup[];
	};

	const submitBadge = () => {
		const imageURL = document.querySelector('input[name="image_url"]') as HTMLInputElement;
		const activityURL = document.querySelector('input[name="activity_url"]') as HTMLInputElement;
		const description = document.querySelector('input[name="description"]') as HTMLInputElement;
		const time = document.querySelector('input[type="datetime-local"]') as HTMLInputElement;
		const category = document.querySelector('input[name="category"]') as HTMLInputElement;

		if (!imageURL.value) {
			error = 'Image URL cannot be empty.';

			return;
		}

		if (
			!imageURL.value.startsWith('http') ||
			(activityURL.value.length > 0 && !activityURL.value.startsWith('http'))
		) {
			error = 'URLs must start with http or https.';

			return;
		}

		badgesPromise = fetch(
			`/api/badges?image=${encodeURIComponent(imageURL.value)}&post=${encodeURIComponent(
				activityURL.value || '#'
			)}${
				description.value.length > 0 ? `&description=${encodeURIComponent(description.value)}` : ''
			}${category.value.length > 0 ? `&category=${encodeURIComponent(category.value)}` : ''}${
				time.valueAsDate ? `&time=${encodeURIComponent(dateToDatabaseTime(time.valueAsDate))}` : ''
			}${
				selectedBadge && selectedBadge.id ? `&update=${encodeURIComponent(selectedBadge.id)}` : ''
			}`,
			{
				method: 'PUT'
			}
		);

		error = null;
		imageURL.value = '';
		activityURL.value = '';
		description.value = '';
		category.value = '';
		selectedBadge = undefined;
	};

	const removeAllBadges = () => {
		if (confirmPrune === 2) {
			confirmPrune = 0;
		} else if (confirmPrune === 0) {
			confirmPrune = 1;

			return;
		} else {
			confirmPrune = 2;

			return;
		}

		selectedBadge = undefined;
		badgesPromise = fetch(root(`/api/badges?prune=true`), {
			method: 'DELETE'
		});
	};

	const removeBadge = (badge: Badge) => {
		if (!badge.id) return;

		if (confirmDelete === badge.id * 2) {
			confirmDelete = 0;
		} else if (confirmDelete / 4 === badge.id) {
			confirmDelete = badge.id * 2;

			return;
		} else {
			confirmDelete = badge.id * 2;

			return;
		}

		(document.querySelector(`#badge-${badge.id}`) as HTMLAnchorElement).style.display = 'none';
		selectedBadge = undefined;
		badgesPromise = fetch(root(`/api/badges?id=${badge.id}`), {
			method: 'DELETE'
		});
	};

	// const screenshot = async () => {
	// 	let element = document.querySelector('#badges') as HTMLElement;

	// 	element.classList.add('invert');

	// 	if (element !== null) {
	// 		domToBlob(element, {
	// 			style: {
	// 				backgroundColor: transparent ? 'transparent' : dark ? '#0b1622' : '#edf1f5'
	// 			},
	// 			quality: 1,
	// 			scale: 2,
	// 			fetch: {
	// 				requestInit: {
	// 					mode: 'cors'
	// 				}
	// 				// bypassingCache: true
	// 			}
	// 		}).then((blob) => {
	// 			const downloadWrapper = document.createElement('a');
	// 			const wrappedImageButton = document.getElementById(
	// 				'wrapped-image-download'
	// 			) as HTMLAnchorElement;
	// 			const image = document.createElement('img');
	// 			const object = (window.URL || window.webkitURL || window || {}).createObjectURL(blob);

	// 			downloadWrapper.href = object;
	// 			downloadWrapper.target = '_blank';
	// 			image.src = object;

	// 			downloadWrapper.appendChild(image);

	// 			if (wrappedImageButton !== null) {
	// 				wrappedImageButton.href = object;
	// 			}

	// 			const wrappedFinal = document.getElementById('wrapped-final');

	// 			if (wrappedFinal !== null) {
	// 				wrappedFinal.innerHTML = '';
	// 				wrappedFinal.appendChild(downloadWrapper);
	// 			}

	// 			downloadWrapper.click();
	// 		});

	// 		await new Promise((resolve) => setTimeout(resolve, 1000));

	// 		element.classList.remove('invert');
	// 	}
	// };

	const groupBadges = (badges: Badge[]) => {
		const groupedBadges: GroupedBadges = {};

		// badgeCount = badges.length;

		badges.forEach((badge) => {
			if (!badge.category) badge.category = 'Uncategorised';

			if (!groupedBadges[badge.category]) groupedBadges[badge.category] = [];

			groupedBadges[badge.category].push(badge);
		});

		return Object.entries(groupedBadges)
			.sort((a, b) => a[1].length - b[1].length)
			.reduce((set: GroupedBadges, [key, value]) => {
				set[key] = value;

				return set;
			}, {});
	};

	const thumbnail = (url: string | undefined) => {
		const width = 144;
		const height = 200;

		if (url && url.includes('catbox.moe') && !url.includes('gif'))
			return url.replace('catbox.moe/', 'catbox.moe/thumbs/t_');

		if (url && url.includes('imgur') && !url.includes('gif'))
			return (!url.includes('i.imgur.com') ? url.replace('imgur.com', 'i.imgur.com') : url).replace(
				/(\.\w+)$/,
				`_d.webp?maxwidth=${width}&shape=thumb&fidelity=high`
			);

		if (url && url.includes('discordapp')) {
			const match = url.match(/attachments\/(\d+)\/(\d+)\/(.+)/);

			if (match) {
				const [_, server, id, file] = match;

				return `https://media.discordapp.net/attachments/${server}/${id}/${file}?width=${width}&height=${height}`;
			}
		}

		return url;
	};

	const parsePost = async () => {
		if (importImages && importImages.length > 0) importImages = undefined;

		const link = (document.querySelector('#import_activity_url') as HTMLInputElement).value;
		const type = link.replace(/.*\/(activity|thread)\/(\d+).*/, '$1');
		const id = link.replace(/.*\/(activity|thread)\/(\d+).*/, '$2');

		if (type !== 'activity') return null;

		let text = await activityText(parseInt(id), importReplies);

		const images: ImportImage[] = [];

		if (importLinks) {
			Array.from(new DOMParser().parseFromString(text, 'text/html').querySelectorAll('a')).forEach(
				(a) => {
					const anchor = a as HTMLAnchorElement;

					if (anchor.querySelector('img')) {
						images.push({
							link: anchor.href,
							image: (anchor.querySelector('img') as HTMLImageElement).src
						});
					}
				}
			);

			text = text.replace(/<a.*?>.*?<img.*?>.*?<\/a>/g, '');

			Array.from(
				new DOMParser().parseFromString(text, 'text/html').querySelectorAll('img')
			).forEach((img) => {
				const image = img as HTMLImageElement;

				images.push({
					image: image.src
				});
			});
		} else {
			Array.from(
				new DOMParser().parseFromString(text, 'text/html').querySelectorAll('img')
			).forEach((img) => {
				const image = img as HTMLImageElement;

				images.push({
					image: image.src
				});
			});
		}

		importImages = images;
	};

	const importBadges = () =>
		fetch(
			`/api/badges?import=true
			${importCategory.length > 0 ? `&category=${encodeURIComponent(importCategory)}` : ''}
		`,
			{
				method: 'PUT',
				headers: {
					'Content-Type': 'application/json'
				},
				body: JSON.stringify(
					importImages?.map((image) => ({
						image: image.image,
						post: image.link || '#',
						category: importCategory
					}))
				)
			}
		).then(() => {
			importMode = false;
			importImages = undefined;
		});
</script>

<HeadTitle route={`${data.username}'s Badge Wall`} path={`/user/${data.username}`} />

{#if loadError}
	<Popup fullscreen locked>
		{loadError}
	</Popup>
{:else}
	{#await currentUserIdentity}
		<Message message="Loading user ..." />

		<Skeleton grid={true} count={100} width="150px" height="170px" />
	{:then identity}
		{@const isOwner = identity && (isId ? identity.id : identity.name) === data.username}

		{#await badgesPromise}
			<Message message="Loading badges ..." />

			<Skeleton grid={true} count={100} width="150px" height="170px" />
		{:then badgesResponse}
			{#if badgesResponse}
				{#await badgesResponse.json()}
					<Message message="Parsing badges ..." />

					<Skeleton grid={true} count={100} width="150px" height="170px" />
				{:then ungroupedBadges}
					<div id="badges">
						{#await awcPromise then badges}
							{#await badges.text() then text}
								{@const parsedBadges = awcBadgesGrouped(text)}

								{#if parsedBadges.length > 0}
									{#each parsedBadges as group}
										<details open>
											<summary>
												Anime Watching Club <span class="opaque">|</span>
												{group.group}
											</summary>

											<p />

											<div class="badges">
												{#each group.badges as badge}
													<a
														href={badge.link}
														target="_blank"
														class="badge"
														id={`badge-${badge.link}`}
														title={badge.description}
														use:tooltip
													>
														<FallbackImage
															source={cdn(thumbnail(badge.image))}
															alternative={badge.description}
															fallback={thumbnail(badge.image)}
														/>
													</a>
												{/each}
											</div>
										</details>

										<p />
									{/each}
								{/if}
							{/await}
						{/await}

						{#if ungroupedBadges === null}
							<Message message="Loading badges ..." />

							<Skeleton grid={true} count={10} width="150px" height="170px" />
						{:else}
							{@const groupedBadges = Object.entries(groupBadges(ungroupedBadges))}

							{#if isOwner}
								<div class="card">
									<a href={root(`/user/${data.username}`)}>{$locale().user.badges.backToProfile}</a>
									<span style="margin: 0 0.625rem;">•</span>
									<button
										on:click={() => {
											if (editMode) selectedBadge = undefined;

											editMode = !editMode;
										}}
									>
										{editMode
											? $locale().user.badges.editMode.disable
											: $locale().user.badges.editMode.enable}
									</button>
									<span style="margin: 0 0.625rem;">•</span>
									<button
										on:click={() => {
											if (importMode) selectedBadge = undefined;

											importMode = !importMode;
										}}
									>
										{importMode
											? $locale().user.badges.importMode.disable
											: $locale().user.badges.importMode.enable}
									</button>

									{#if editMode && isOwner}
										{@const groups = groupedBadges
											.map((group) => group[0])
											.filter((group) => group !== 'Uncategorised')}

										<p />

										{#if error}
											<p style="color: red;">{error}</p>
										{/if}

										<input
											type="text"
											placeholder={$locale().user.badges.editMode.imageURL}
											name="image_url"
											minlength="1"
											maxlength="1000"
											size="15"
											value={selectedBadge ? selectedBadge.image : ''}
										/>
										<input
											type="text"
											placeholder={$locale().user.badges.editMode.activityURL}
											name="activity_url"
											minlength="1"
											maxlength="1000"
											size="15"
											value={selectedBadge
												? selectedBadge.post === '#'
													? ''
													: selectedBadge.post
												: ''}
										/>
										<input
											type="text"
											placeholder={$locale().user.badges.editMode.description}
											name="description"
											minlength="1"
											maxlength="1000"
											size="15"
											value={selectedBadge ? selectedBadge.description : ''}
										/>
										<Dropdown
											items={groups.map((group) => ({
												name: group,
												url: '#',
												onClick: () => {
													const category = document.querySelector('input[name="category"]');

													if (category instanceof HTMLInputElement) category.value = group;
												}
											}))}
											header={false}
											center={false}
										>
											<span slot="title">
												<input
													type="text"
													placeholder={$locale().user.badges.editMode.category}
													name="category"
													minlength="1"
													maxlength="1000"
													size="15"
													value={selectedBadge
														? selectedBadge.category === 'Uncategorised'
															? ''
															: selectedBadge.category
														: ''}
													list="categories"
												/>
											</span>
										</Dropdown>
										<button class="button-lined" on:click={submitBadge}
											>{selectedBadge
												? $locale().user.badges.editMode.update
												: $locale().user.badges.editMode.add}</button
										>
										{#if selectedBadge}
											{$locale().user.badges.editMode.or}
											<button
												class="button-lined"
												on:click={() => {
													if (selectedBadge) removeBadge(selectedBadge);
												}}>{$locale().user.badges.editMode.delete}</button
											>
										{/if}
										<span style="float: right;">
											<input
												type="datetime-local"
												value={selectedBadge && selectedBadge.time ? selectedBadge.time : ''}
											/>
											<small>Must be full date and time, defaults to now if any fields empty</small>
										</span>
									{/if}
								</div>
							{/if}

							<p />

							{#if ungroupedBadges.length === 0}
								<div class="card">
									No due.moe registered badges found for this user. <a
										href={'#'}
										title="This alert does not include AWC badges."
										use:tooltip>?</a
									>
								</div>
							{/if}

							{#each groupedBadges as [category, badges]}
								<details open>
									<summary>{category}</summary>

									<p />

									<div class="badges">
										{#each badges as badge}
											{#if editMode}
												<a
													href={`#`}
													on:click={() => (selectedBadge = badge)}
													id={`badge-${badge.id}`}
													title={`${
														badge.time ? databaseTimeToDate(badge.time).toLocaleString() : ''
													}${badge.description ? `\n${badge.description}` : ''}`}
													use:tooltip
												>
													<FallbackImage
														source={cdn(thumbnail(badge.image))}
														alternative={badge.description}
														fallback={thumbnail(badge.image)}
													/>
												</a>
											{:else}
												<a
													href={badge.post}
													target="_blank"
													id={`badge-${badge.id}`}
													class="badge"
													title={`${
														badge.time ? databaseTimeToDate(badge.time).toLocaleString() : ''
													}${badge.description ? `\n${badge.description}` : ''}`}
													use:tooltip
												>
													<FallbackImage
														source={cdn(thumbnail(badge.image))}
														alternative={badge.description}
														fallback={thumbnail(badge.image)}
													/>
												</a>
											{/if}
										{/each}
									</div>
								</details>

								{#if groupedBadges[groupedBadges.length - 1][0] !== category}
									<p />
								{/if}
							{/each}
						{/if}
					</div>
				{:catch}
					<Popup fullscreen locked>Could not parse badges</Popup>
				{/await}
			{:else}
				<Message message="Loading badges ..." />

				<Skeleton grid={true} count={100} width="150px" height="170px" />
			{/if}
		{:catch}
			<Popup fullscreen locked>Could not fetch badges</Popup>
		{/await}
	{:catch}
		<AnimeRateLimited>This user's badges could not be loaded.</AnimeRateLimited>
	{/await}
{/if}

{#if true}
	<Popup fullscreen onLeave={() => (importMode = false)} show={importMode}>
		{$locale().user.badges.importMode.title}

		<p />

		<input
			type="text"
			placeholder={$locale().user.badges.editMode.activityURL}
			id="import_activity_url"
			minlength="1"
			maxlength="1000"
			size="20"
		/>
		<input
			type="text"
			placeholder={$locale().user.badges.editMode.category}
			id="import_category"
			minlength="1"
			maxlength="1000"
			size="20"
		/>

		<p />

		<input type="checkbox" id="import_links" name="import_links" bind:checked={importLinks} />
		{$locale().user.badges.importMode.importLinks.title}
		<SettingHint lineBreak>
			{$locale().user.badges.importMode.importLinks.hint}
		</SettingHint>

		<p />

		<input type="checkbox" id="import_links" name="import_links" bind:checked={importReplies} />
		{$locale().user.badges.importMode.importReplies}

		<p />

		<button
			on:click={() => {
				importMode = false;
				importImages = undefined;
			}}
			class="button-lined"
		>
			{$locale().user.badges.importMode.cancel}
		</button>
		<button on:click={() => parsePost()} class="button-lined" style="float: right;">
			{$locale().user.badges.importMode.fetch}
		</button>

		<p />

		<details>
			<summary>{$locale().user.badges.importMode.dangerous}</summary>

			<button
				class="button-lined no-shadow"
				data-umami-event="Remove All Badges"
				on:click={removeAllBadges}
			>
				{$locale({
					values: {
						times: 3 - confirmPrune
					}
				}).user.badges.importMode.deleteAll.title}
			</button>
			<SettingHint lineBreak>
				{$locale().user.badges.importMode.deleteAll.hint}
			</SettingHint>
		</details>

		{#if importImages && importImages.length > 0}
			<p />

			{$locale({
				values: {
					count: importImages.length
				}
			}).user.badges.importMode.importConfirm}&nbsp;
			<button
				on:click={() => importBadges()}
				class="button-lined no-shadow"
				data-umami-event="Import Badges"
			>
				{$locale().user.badges.importMode.import}
			</button>

			<SettingHint lineBreak>
				{$locale().user.badges.importMode.importWait}
			</SettingHint>
		{/if}
	</Popup>
{/if}

<style>
	/* body {
		margin: 0;
		padding: 0;
		text-align: center;
		background-color: #151f2e;
	} */

	img {
		width: 100%;
		height: auto;
	}

	.badges {
		display: grid;
		grid-template-columns: repeat(auto-fill, minmax(8%, 1fr));
		gap: 0.25rem;
	}

	:global(.invert *) {
		filter: invert(0) !important;
	}

	.badge {
		display: flex;
		flex-direction: column;
		justify-content: center;
		align-items: center;
		transition: transform 0.3s ease;
		box-sizing: border-box;
	}

	.badge img {
		border-radius: 8px;
	}

	.badge:hover {
		transform: scale(1.1);
		position: relative;
		z-index: 2;
		transition: transform 0.3s ease;
	}
</style>
